package tau.pimpmyfreedb.GUI;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;

import tau.facebook.FacebookBrowser;
import tau.pimpmyfreedb.common.IProgressUpdateClient;
import tau.pimpmyfreedb.common.types.User;
import tau.pimpmyfreedb.dal.DalResponse;
import tau.pimpmyfreedb.dal.IDataItem;
import tau.pimpmyfreedb.master.Callback;
import tau.pimpmyfreedb.master.GuiCallback;
import tau.pimpmyfreedb.master.IPimpMaster;

public class WelcomeWindow implements IProgressUpdateClient {
    public final String STATUS_READY = "Please select a user and login";

    // data members

    private IPimpMaster master;
    private IDataItem[] users;
    private boolean disposeLoginWindow;

    // other windows

    private FacebookLoginWindow fbLoginWindow;

    // gui controls

    private Shell shell;
    private Label lblInstructions;
    private Label lblStatus;
    private Button btnDeleteUser;
    private Button btnAddUser;
    private Button btnLogin;
    private List lstUsers;
    private Image bgImage;

    public WelcomeWindow(IPimpMaster master) {
	this.master = master;
	this.disposeLoginWindow = false;
	shell = CreateShell();
	createLoginWindow();
    }

    // gui

    private Shell CreateShell() {

	// the shell
	final Shell shell = SWTUtil.getShell();
	GridLayout shellLayout = new GridLayout(1, false);
	shell.setLayout(shellLayout);
	shell.setSize(520, 530);
	shell.addDisposeListener(new DisposeListener() {

	    @Override
	    public void widgetDisposed(DisposeEvent arg0) {
		if (bgImage != null)
		    bgImage.dispose();
		if (fbLoginWindow != null) {
		    disposeLoginWindow = true;
		    fbLoginWindow.getShell().dispose();
		}

		master.closeWelcomeScreen();
	    }
	});

	shell.setText("PimpMyFreeDB Login");

	// the composite
	Composite rightComposite = new Composite(shell, SWT.NONE);
	GridLayout rightCompositeLayout = new GridLayout(2, false);
	rightCompositeLayout.marginTop = 100;
	rightComposite.setLayout(rightCompositeLayout);
	GridData rightGridData = new GridData();
	rightGridData.horizontalAlignment = SWT.RIGHT;
	rightGridData.grabExcessHorizontalSpace = true;
	rightComposite.setLayoutData(rightGridData);
	rightComposite.setBackground(SWTUtil.getDisplay().getSystemColor(
		SWT.COLOR_WHITE));

	// background
	bgImage = new Image(SWTUtil.getDisplay(), shell.getBounds());
	GC gc = new GC(bgImage);
	gc.drawImage(new Image(SWTUtil.getDisplay(), "images/pimp1.jpg"), 0, 0);
	gc.dispose();
	shell.setBackgroundImage(bgImage);

	// instructions label
	GridData lblGridData = new GridData();
	lblGridData.horizontalAlignment = SWT.FILL;
	lblGridData.horizontalSpan = 2;
	lblGridData.heightHint = 25;

	lblInstructions = new Label(rightComposite, SWT.NONE);
	lblInstructions.setText("Please select a user and login");
	lblInstructions.setLayoutData(lblGridData);
	lblInstructions.setBackground(SWTUtil.getDisplay().getSystemColor(
		SWT.COLOR_WHITE));

	// listbox
	GridData listGridData = new GridData();
	listGridData.verticalSpan = 3;
	listGridData.verticalAlignment = SWT.TOP;
	listGridData.horizontalAlignment = SWT.FILL;
	listGridData.verticalAlignment = SWT.FILL;
	listGridData.heightHint = 200;
	listGridData.widthHint = 150;
	lstUsers = new List(rightComposite, SWT.V_SCROLL | SWT.BORDER);
	lstUsers.setLayoutData(listGridData);
	lstUsers.addMouseListener(new MouseAdapter() {
	    public void mouseDoubleClick(MouseEvent arg0) {
		if (lstUsers.getSelectionIndex() != -1) {
		    login();
		}
	    }
	});

	// login button
	GridData btnGridData = new GridData();
	btnGridData.verticalAlignment = SWT.TOP;
	btnLogin = new Button(rightComposite, SWT.PUSH);
	btnLogin.setText("Login");
	btnLogin.setLayoutData(btnGridData);
	btnLogin.addSelectionListener(new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {
		login();
	    }
	});
	shell.setDefaultButton(btnLogin);

	// add user button
	btnAddUser = new Button(rightComposite, SWT.PUSH);
	btnAddUser.setText("Add...");
	btnAddUser.setLayoutData(btnGridData);
	btnAddUser.addSelectionListener(new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {
		addNewUser();
	    }
	});

	// delete user button
	btnDeleteUser = new Button(rightComposite, SWT.PUSH);
	btnDeleteUser.setText("Delete");
	btnDeleteUser.setLayoutData(btnGridData);
	btnDeleteUser.addSelectionListener(new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {
		deleteUser();
	    }
	});

	lblGridData = new GridData();
	lblGridData.horizontalAlignment = SWT.FILL;
	lblGridData.horizontalSpan = 2;
	lblGridData.heightHint = 60;

	lblStatus = new Label(rightComposite, SWT.BORDER | SWT.CENTER
		| SWT.WRAP);
	lblStatus.setLayoutData(lblGridData);
	lblStatus.setForeground(SWTUtil.getDisplay().getSystemColor(
		SWT.COLOR_INFO_FOREGROUND));
	lblStatus.setBackground(SWTUtil.getDisplay().getSystemColor(
		SWT.COLOR_INFO_BACKGROUND));

	return shell;
    }

    private void createLoginWindow() {
	fbLoginWindow = new FacebookLoginWindow(shell);
	fbLoginWindow.setOnLoginComplete(createFacebookLoginCompleteCallback());
	fbLoginWindow.getShell().addDisposeListener(new DisposeListener() {

	    @Override
	    public void widgetDisposed(DisposeEvent arg0) {
		if (!disposeLoginWindow)
		    createLoginWindow();
	    }
	});
    }

    public void disableControls() {
	btnAddUser.setEnabled(false);
	btnLogin.setEnabled(false);
	lstUsers.setEnabled(false);
	btnDeleteUser.setEnabled(false);
    }

    public void enableControls() {
	lblStatus.setText(STATUS_READY);
	btnAddUser.setEnabled(true);
	btnLogin.setEnabled(true);
	lstUsers.setEnabled(true);
	btnDeleteUser.setEnabled(true);
    }

    // getters & setters

    public Shell getShell() {
	return shell;
    }

    public void setStatus(String msg) {
	lblStatus.setText(msg);
    }

    public void setUsers(IDataItem[] users) {
	this.users = users;

	lstUsers.removeAll();
	for (int i = 0; i < users.length; i++)
	    lstUsers.add(users[i].getName());
	lstUsers.select(0);
    }

    // buttons

    private Callback<FacebookBrowser> createFacebookLoginCompleteCallback() {
	final IProgressUpdateClient progressClient = this;
	GuiCallback<FacebookBrowser> callback = new GuiCallback<FacebookBrowser>(
		shell) {

	    @Override
	    public void guiExecute(FacebookBrowser param) {

		// adjust the gui
		disableControls();
		setStatus("Adding the new user to the database...");

		fbLoginWindow.getShell().dispose();
		String name = null;
		String fbToken = null;
		try {
		    name = param.GetFacebookAPIObject().getUserName();
		    fbToken = param.GetFacebookAPIObject().getToken();

		} catch (Exception ex) {
		    setStatus("Failed to get user from facebook. Please try again.");
		}
		if (name == null || fbToken == null) {
		    enableControls();
		    return;
		}

		// add the user
		User user = new User(IDataItem.NewItemId, name, fbToken);
		// The Master adds the user to the DB and executes this callback
		// when it is done.
		master.addNewUser(user, progressClient,
			new GuiCallback<DalResponse>() {
			    @Override
			    public void guiExecute(DalResponse param) {
				updateUsersList();
			    }
			});

	    }
	};

	return callback;
    }

    private void login() {
	int userID = getSelectedUserID();
	if (userID > -1) {
	    master.login(userID);
	}
    }

    private int getSelectedUserID() {
	int selectedIndex = lstUsers.getSelectionIndex();
	if (selectedIndex < 0 || selectedIndex >= users.length)
	    return -1;

	int userId = users[selectedIndex].getDataId();
	return userId;
    }

    private void deleteUser() {
	master.deleteUser(getSelectedUserID());
    }

    private void addNewUser() {
	fbLoginWindow.getShell().open();
	fbLoginWindow.getShell().setFocus();
    }

    public void updateUsersList() {
	// get users
	setStatus("Getting users list from the database...");
	master.getDal().getUsersList(new GuiCallback<IDataItem[]>(getShell()) {
	    @Override
	    public void guiExecute(IDataItem[] param) {
		setUsers(param);
		enableControls();
	    }
	});
    }

    @Override
    public void handleProgressUpdate(int percentage, final String message) {
	shell.getDisplay().asyncExec(new Runnable() {
	    @Override
	    public void run() {
		setStatus(message);
	    }
	});
    }

    @Override
    public void handleOperationComplete() {
	shell.getDisplay().asyncExec(new Runnable() {
	    @Override
	    public void run() {
		setStatus(STATUS_READY);
	    }
	});
    }

    @Override
    public boolean isCancelled() {
	return false;
    }

    public void showDBErrorMessage(String message) {
	SWTUtil.errorBox("Couldn't connect to DB: " + message);
    }

}
